/*
    * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    *     http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
 */

#include <thread>
#include <securec.h>
#include <atomic>
#include <unistd.h>

#include "hisysevent.h"
#include "iservice_registry.h"
#include "system_ability_definition.h"

#include "file_share_client.h"


namespace OHOS {
namespace FileShare {
namespace {
    constexpr int32_t GET_SERVICE_MAX_COUNT = 3;
    constexpr uint32_t WAIT_MS = 200;
}

int32_t FileShareClient::SendFile(SendTask &task)
{
    LOGD("SendFile start.");
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->SendFile(task);
}

int32_t FileShareClient::RegisterFileShareCallback(const sptr<IFileShareCallback> &callback)
{
    LOGD("RegisterFileShareCallback start.");

    CHKPTR(callback, FS_NULL_PARAM);

    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->RegisterFileShareCallback(callback);
}

int32_t FileShareClient::UnRegisterFileShareCallback()
{
    LOGD("UnRegisterFileShareCallback start.");

    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->UnRegisterFileShareCallback();
}

int32_t FileShareClient::GetRemoteProxy()
{
    std::lock_guard<std::mutex> clientLock(clientMutex_);
    if (fileshareProxy_ != nullptr) { 
        LOGD("fileshareProxy_ already init");
        return FS_SUCCESS;
    }

    auto systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    CHKPTR(systemManager, FS_GET_SA_MANAGER_FAILED);
    int32_t retry = 0;
    while (retry < GET_SERVICE_MAX_COUNT) {
        fileshareProxy_ = iface_cast<IFileShareService>(systemManager->GetSystemAbility(FILE_SHARE_SERVICE_ID));
        if (fileshareProxy_ != nullptr) {
            LOGI("fileshareProxy_ get service success, retry:%{public}d", retry);
            serviceDeathObserver_ = new (std::nothrow) FileShareDeathRecipient(*const_cast<FileShareClient *>(this));
            if (serviceDeathObserver_ != nullptr) {
                fileshareProxy_->AsObject()->AddDeathRecipient(serviceDeathObserver_);
            } else {
                return FS_NEW_DEATH_RECIPIENT_FAILED;
            }
            return FS_SUCCESS;
        }
        LOGW("get system ability failed, retry:%{public}d", retry);
        std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_MS));
        retry++;
    }
    LOGE("Get file share service failed");
    return FS_GET_PROXY_FAILED;
}

void FileShareClient::OnDeath(const wptr<IRemoteObject> &remote)
{
    std::lock_guard<std::mutex> clientLock(clientMutex_);
    LOGE("file share service is dead.");
    (void)remote;
    serviceDeathObserver_ = nullptr;
    fileshareProxy_ = nullptr;
}

int32_t FileShareClient::CancelSendFile(const std::string &deviceId, SendType type)
{
    if (deviceId.empty()) {
        LOGE("deviceId is empty.");
        return FS_INVALID_PARAM;
    }

    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->CancelSendFile(deviceId, type);
}

int32_t FileShareClient::SetShareStatus(const bool status)
{
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->SetShareStatus(status);
}

int32_t FileShareClient::GetShareStatus(bool &status)
{
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->GetShareStatus(status);
}

std::string FileShareClient::GetStoragePath()
{
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS || fileshareProxy_ == nullptr) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return "";
    }
    return fileshareProxy_->GetStoragePath();
}

int32_t FileShareClient::SetStoragePath(std::string &path)
{
    if (path.empty()) {
        LOGE("path is empty.");
        return FS_INVALID_PARAM;
    }
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->SetStoragePath(path);
}

int32_t FileShareClient::GetWorkDuration()
{
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->GetWorkDuration();
}

int32_t FileShareClient::SetWorkDuration(int32_t &time)
{
    if (time < 0) {
        LOGE("time <0");
        return FS_INVALID_PARAM;
    }
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->SetWorkDuration(time);
}

int32_t FileShareClient::RegisterShareStatusCallback(const std::string &bundleName, const sptr<IFileShareCallback> &callback)
{
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->RegisterShareStatusCallback(bundleName, callback);
}

int32_t FileShareClient::UnRegisterShareStatusCallback(const std::string &bundleName)
{
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->UnRegisterShareStatusCallback(bundleName);
}

int32_t FileShareClient::ChangeUuid(const uint16_t uuid)
{
    if (uuid == 0) {
        LOGE("ChangeUuid failed, uuid is 0.");
        return FS_INVALID_PARAM;
    }
    
    auto ret = GetRemoteProxy();
    if (ret != FS_SUCCESS) {
        LOGE("GetRemoteProxy failed, ret : %{public}d", ret);
        return ret;
    }
    CHKPTR(fileshareProxy_, FS_NULL_PARAM);
    return fileshareProxy_->ChangeUuid(uuid);
}
} // namespace FileShare
} // namespace OHOS    